import re

from QQLoginTool.QQtool import OAuthQQ
from django import http
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.views import View
from django.conf import settings
from django.http import HttpResponse, HttpResponseForbidden
from django_redis import get_redis_connection

from libs import sinaweibopy3
from oauth import constants
from oauth.models import OAuthQQUser, OAuthSinaUser
from oauth.utils import encode_openid, decode_openid
from users.models import User


# Create your views here.
from utils import meiduo_signature


class QQAuthURLView(View):
    def get(self, request):
        # 返回一个qq扫描授权页面
        # 根据qq_login_tool这个工具生成qq登录url

        # 生成一个oauth对象, 通过这个对象获取 url 和 access_token 和 openid
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI, state=next)

        # 生成qq扫描登录链接
        qq_login_url = oauth.get_qq_url()

        # 让浏览器重定向到登录页面去
        return redirect(qq_login_url)
        pass


class QQAuthUserView(View):
    def get(self, request):
        # http://www.meiduo.site:8000/oauth_callback?code=FF671ACAF1EC7FFB4DFC860B9159B6FA&state=%3Cbuilt-in%2Bfunction%2Bnext%3E

        # 1, 接收数据
        code = request.GET.get('code')

        # 2, 校验数据
        if not code:
            return HttpResponseForbidden('code丢失!')

        # 3, 处理业务
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI, state='/')

        # 通过code 获取 access_token
        access_token = oauth.get_access_token(code)

        # 通过access_token 获取 openid

        openid = oauth.get_open_id(access_token)

        ####
        # 判断openid是否已经绑定过, 如果绑定过,就取user , 进行登录
        # 1, 判断openid是否已经绑定过
        try:
            user_openid = OAuthQQUser.objects.get(openid=openid)
        except Exception as e:
            print(e)
            # 4, 如果没有绑定过, 就显示绑定页面

            # 4,1, 加密openid
            sign_openid = encode_openid(openid)

            context = {
                'openid': sign_openid,
            }
            return render(request, 'oauth_callback.html', context=context)

        # 取关联用户
        user = user_openid.user

        # 登录用户
        login(request, user)

        # 保持状态
        response = redirect('/')
        request.session.set_expiry(None)  # 按照默认配置, (2周)
        response.set_cookie('username', user.username, expires=3600 * 24 * 14)

        # 4, 返回响应
        # 4,1 重定向到首页
        return response

        ####

    def post(self, request):
        # 1, 接收数据
        sign_open_id = request.POST.get('openid')
        mobile = request.POST.get('mobile')
        pwd = request.POST.get('pwd')
        sms_code = request.POST.get('sms_code')
        # 2, 校验数据
        if not all([sign_open_id, mobile, pwd, sms_code]):
            return HttpResponseForbidden('参数不全')

        # 2,1 解密出openid
        open_id= decode_openid(sign_open_id)

        if not open_id:
            return HttpResponseForbidden('openid不正确')

        # 2,3 校验手机号的格式
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseForbidden("手机号格式有误")

        # 2,4 校验密码的格式
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', pwd):
            return HttpResponseForbidden("密码格式有误")

        # 2,5 校验短信验证码的正确性
        redis_conn = get_redis_connection("verify_code")
        redis_sms_code = redis_conn.get(mobile)

        if redis_sms_code:
            redis_sms_code = redis_sms_code.decode()

        if sms_code != redis_sms_code:
            return HttpResponseForbidden("短信验证码填写错误")

        # 3, 处理业务
        # 根据手机号获取已注册的用户
        try:
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            # 3,1 创建user
            user = User.objects.create_user(username=mobile, password=pwd, mobile=mobile)
            # 3,2 绑定openid
            OAuthQQUser.objects.create(user=user, openid=open_id)
            # 3,3 登录
            login(request, user)
            # 3,4 保持状态
            response = redirect('/')

            request.session.set_expiry(None)  # 按照默认配置, (2周)
            response.set_cookie('username', user.username, expires=3600 * 24 * 14)

            # 4, 返回响应
            # 4,1 重定向到首页
            return response


        # 如果根据手机号获取到了用户, 然后验证他的密码是否正确
        if user.check_password(raw_password=pwd):
            # 如果密码正确, 就进行绑定
            OAuthQQUser.objects.create(user= user, openid=open_id)

            # 3,3 登录
            login(request, user)
            # 3,4 保持状态
            response = redirect('/')

            request.session.set_expiry(None)  # 按照默认配置, (2周)
            response.set_cookie('username', user.username, expires=3600 * 24 * 14)

            # 4, 返回响应
            # 4,1 重定向到首页
            return response

        else:
            # 密码不正确, 就返回结果
            return HttpResponseForbidden('密码不正确')


class OAuthSinaURLView(View):
    def get(self, request):
        next_url = request.GET.get('next')

        # 创建授权对象
        client = sinaweibopy3.APIClient(app_key=settings.WEIBO_APP_KEY, app_secret=settings.WEIBO_APP_SECRET,redirect_uri=settings.WEIBO_REDIRECT_URL)
        # 生成授权地址

        login_url =client.get_authorize_url()

        # 响应
        # return http.JsonResponse({
        #     'code': 0,
        #     'errmsg': "OK",
        #     'login_url': login_url
        # })
        return redirect(login_url)


class OAuthSinaOpenidView(View):
    def get(self, request):
        code = request.GET.get('code')

        client = sinaweibopy3.APIClient(app_key=settings.WEIBO_APP_KEY, app_secret=settings.WEIBO_APP_SECRET,redirect_uri=settings.WEIBO_REDIRECT_URL)

        # 1.根据code获取access_token
        result = client.request_access_token(code)
        client.set_access_token(result.access_token, result.expires_in)
        openid=result.uid
        # 判断是否初次授权
        try:
            qquser = OAuthSinaUser.objects.get(uid=openid)
        except:
            # 未查到数据，则为初次授权，显示绑定页面
            # 将openi加密
            json_str = meiduo_signature.dumps({"openid": openid}, constants.OPENID_EXPIRES)
            # 显示绑定页面
            context = {
                'token': json_str
            }
            return render(request, 'oauth_callback.html', context)
        else:
            # 查询到授权对象，则状态保持，转到相关页面
            user = qquser.user
            login(request, user)

            response = redirect('/')
            response.set_cookie('username', user.username)
            return response

            # return http.HttpResponse(openid)

    def post(self, request):
        # 接收：openid,mobile,password,sms_code
        access_token = request.POST.get('access_token')
        mobile = request.POST.get('mobile')
        pwd = request.POST.get('pwd')
        sms_code = request.POST.get('sms_code')
        state = request.GET.get('state', '/')

        # 验证：参考注册的验证
        openid_dict = meiduo_signature.loads(access_token, constants.OPENID_EXPIRES)
        if openid_dict is None:
            return http.HttpResponseForbidden('授权信息无效，请重新授权')
        openid=openid_dict.get('openid')

        # 处理：初次授权，完成openid与user的绑定
        # 1.判断手机号是否已经使用
        try:
            user = User.objects.get(mobile=mobile)
        except:
            # 2.如果未使用，则新建用户
            user = User.objects.create_user(mobile, password=pwd, mobile=mobile)
        else:
            # 3.如果已使用，则验证密码
            # 3.1密码正确，则继续执行
            if not user.check_password(pwd):
                # 3.2密码错误，则提示
                return http.HttpResponseForbidden('手机号已经使用，或密码错误')

        # 4.绑定：新建OAuthSinaUser对象
        qquser = OAuthSinaUser.objects.create(
            user=user,
            uid=openid
        )
        # 状态保持
        login(request, user)
        response = redirect(state)
        response.set_cookie('username', user.username)

        # 响应
        return response
